package com.example.esclient.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.esclient.utils.DateUtil;
import com.example.esclient.utils.ElasticsearchUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.nio.entity.NStringEntity;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author zl
 * @Title: ${file_name}
 * @Package ${package_name}
 * @Description: ${todo}
 * @date 2018/8/3114:40
 */
@RestController
@RequestMapping("/es")
public class EsController {
    private static final Logger logger = LoggerFactory.getLogger(EsController.class);

    /**
     * 测试索引
     */
    private String indexName = "resthighindex";

    /**
     * 类型
     */
    private String esType = "normal";

    @Autowired
    private RestHighLevelClient client;

    /**
     * 首页
     *
     * @return
     */
    @RequestMapping("/index")
    public String index() {
        return "index";
    }


    /**
     * http://localhost:8080/es/createIndex
     * 创建索引
     *
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("/createIndex")
    @ResponseBody
    public String createIndex(HttpServletRequest request, HttpServletResponse response) {
//        CreateIndexRequest cir = new CreateIndexRequest("");
//        //设置分片
//        //request.settings(Settings.builder().put("index.number_of_shards",3).put("index.number_of_replicas",2));
//        //设置index的mapping
//        Map<String, Object> jsonMap = new HashMap<>();
//        Map<String, Object> number = new HashMap<>();
//        number.put("type", "text");
//        Map<String, Object> price = new HashMap<>();
//        price.put("type", "float" );
//        Map<String, Object> title = new HashMap<>();
//        title.put("type", "text");
//        Map<String, Object> province = new HashMap<>();
//        province.put("type", "text");
//        Map<String, Object> publishTime = new HashMap<>();
//        publishTime.put("type", "date");
//        Map<String, Object> properties = new HashMap<>();
//        properties.put("number", number);
//        properties.put("price", price);
//        properties.put("title", title);
//        properties.put("province", province);
//        properties.put("publishTime", publishTime);
//        Map<String, Object> book = new HashMap<>();
//        book.put("properties", properties);
//        jsonMap.put("books", book);
//        cir.mapping("type", jsonMap);
//        client.indices().create(cir);

        if (!ElasticsearchUtil.checkIndexExist(indexName)) {
            if (ElasticsearchUtil.createIndex(indexName)) {
                return "索引创建成功";
            } else {
                return "索引已经失败";
            }
        } else {
            return "索引已经存在";
        }
    }

    /**
     * 删除索引
     *
     * @throws IOException
     */
    public void deleteIndex() throws IOException {
        GetIndexRequest getIndexRequest = new GetIndexRequest();
        getIndexRequest.indices("indexName");
        if (client.indices().exists(getIndexRequest)) {
            DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("indexName");
            client.indices().delete(deleteIndexRequest);
        }
    }

    /**
     * 插入记录
     * http://localhost:8080/es/addData
     *
     * @return
     */
    @RequestMapping("/addData")
    @ResponseBody
    public String addData() {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id", DateUtil.formatDate());
        jsonObject.put("age", 29);
        jsonObject.put("name", "liming");
        jsonObject.put("date", new Date());
        String id = ElasticsearchUtil.addData(indexName, esType, jsonObject.getString("id"), jsonObject);
        if (StringUtils.isNotBlank(id)) {
            return "插入成功";
        } else {
            return "插入失败";
        }
    }

    /**
     * 查询所有
     *
     * @return
     */
    @RequestMapping("/queryAll")
    @ResponseBody
    public String queryAll() {
        try {
            HttpEntity entity = new NStringEntity(
                    "{ \"query\": { \"match_all\": {}}}",
                    ContentType.APPLICATION_JSON);
            String endPoint = "/" + indexName + "/" + esType + "/_search";
            Response response = ElasticsearchUtil.getLowLevelClient().performRequest("POST", endPoint, Collections.<String, String>emptyMap(), entity);
            return EntityUtils.toString(response.getEntity());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "查询数据出错";
    }

    /**
     * 根据条件查询
     *
     * @return
     */
    @RequestMapping("/queryByMatch")
    @ResponseBody
    public String queryByMatch() {
        try {
            String endPoint = "/" + indexName + "/" + esType + "/_search";
            IndexRequest indexRequest = new IndexRequest();
            XContentBuilder builder;
            try {
                builder = JsonXContent.contentBuilder()
                        .startObject()

//                            .startObject("query")
//                                .startObject("match")
//                                    .field("name.keyword", "liming")
//                                .endObject()
//                            .endObject()

                        .startObject("query")
                        .startObject("wildcard")
                        .field("name", "liming")
                        .endObject()
                        .endObject()

                        .startObject("highlight")
                        .startObject("fields")
                        .startObject("name")
//                                    .field("pre_tags","<em>")
//                                    .field("post_tags","</em>")
                        .endObject()
                        .endObject()
                        .endObject()

                        .endObject();
                indexRequest.source(builder);
            } catch (IOException e) {
                e.printStackTrace();
            }

            String source = indexRequest.source().utf8ToString();

            logger.info("source---->" + source);

            HttpEntity entity = new NStringEntity(source, ContentType.APPLICATION_JSON);

            Response response = ElasticsearchUtil.getLowLevelClient().performRequest("POST", endPoint, Collections.<String, String>emptyMap(), entity);

            return EntityUtils.toString(response.getEntity());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "查询数据出错";
    }

    /**
     * 高亮
     *
     * @return
     */
    @RequestMapping("/test")
    @ResponseBody
    public String test() {
//        RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")));

        // 这个sourcebuilder就类似于查询语句中最外层的部分。包括查询分页的起始，
        // 查询语句的核心，查询结果的排序，查询结果截取部分返回等一系列配置
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        try {
            // 结果开始处
            sourceBuilder.from(0);
            // 查询结果终止处
            sourceBuilder.size(2);
            // 查询的等待时间
            sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

            /**
             * 使用QueryBuilder
             * termQuery("key", obj) 完全匹配
             * termsQuery("key", obj1, obj2..)   一次匹配多个值
             * matchQuery("key", Obj) 单个匹配, field不支持通配符, 前缀具高级特性
             * multiMatchQuery("text", "field1", "field2"..);  匹配多个字段, field有通配符忒行
             * matchAllQuery();         匹配所有文件
             */
            MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", "费德勒");

            //分词精确查询
//            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("tag", "体育");


//            // 查询在时间区间范围内的结果  范围查询
//            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("publishTime");
//            rangeQueryBuilder.gte("2018-01-26T08:00:00Z");
//            rangeQueryBuilder.lte("2018-01-26T20:00:00Z");

            // 等同于bool，将两个查询合并
            BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();
            boolBuilder.must(matchQueryBuilder);
//            boolBuilder.must(termQueryBuilder);
//            boolBuilder.must(rangeQueryBuilder);
            sourceBuilder.query(boolBuilder);

            // 排序
//            FieldSortBuilder fsb = SortBuilders.fieldSort("date");
//            fsb.order(SortOrder.DESC);
//            sourceBuilder.sort(fsb);

            SearchRequest searchRequest = new SearchRequest("es");
            searchRequest.types("person");
            searchRequest.source(sourceBuilder);
            SearchResponse response = client.search(searchRequest);
            System.out.println(response);
            client.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 高亮
     * @return
     */
    @RequestMapping("/test1")
    @ResponseBody
    public SearchResponse test1() {
        //指定索引库类型
        SearchRequest searchRequest = new SearchRequest("es").types("person");

        try {

            //搜索体（可以添加多个搜索参数）
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            QueryStringQueryBuilder queryBuilder = new QueryStringQueryBuilder("水电");
            queryBuilder.field("desc");
            //构建高亮体
            HighlightBuilder highlightBuilder = new HighlightBuilder();
//            highlightBuilder.preTags("<span style=\"color:red\">");
//            highlightBuilder.postTags("</span>");
            //高亮字段
            highlightBuilder.field("desc").requireFieldMatch(false);
            ;
            //搜索体（添加多个搜索参数）
            searchSourceBuilder.highlighter(highlightBuilder);
            searchSourceBuilder.query(queryBuilder);
            searchRequest.source(searchSourceBuilder);
//            searchSourceBuilder.from(0).size(100);
            //执行查询
            SearchResponse response = client.search(searchRequest);

            //获取搜索的文档结果
            SearchHits hit = response.getHits();
            SearchHit[] hits = hit.getHits();
            for (SearchHit searchHit : hits) {
                //将文档中的每一个对象转换json串值
                String sourceAsString = searchHit.getSourceAsString();
                //将json串值转换成对应的实体对象
                //RecogcardInfo recogcardInfo = JSON.parseObject(sourceAsString, RecogcardInfo.class);
                //获取对应的高亮域
                Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
                //高亮字段
                HighlightField highlightAddress = highlightFields.get("desc");
                if (highlightAddress != null) {
                    // 为title串值增加自定义的高亮标签
                    Text[] titleTexts = highlightAddress.fragments();
                    String address = "";
                    for (Text text : titleTexts) {
                        address += text;
                        System.out.println("address:" + address);
                    }
                    //将追加了高亮标签的串值重新填充到对应的对象
                    //recogcardInfo.setAddress(address);
                }
//                list.add(recogcardInfo);
            }
            return response;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 复合查询
     *
     * @return
     */
    @RequestMapping("/queryByCompound")
    @ResponseBody
    public String queryByCompound() {
        try {
            String endPoint = "/" + indexName + "/" + esType + "/_search";

            IndexRequest indexRequest = new IndexRequest();
            XContentBuilder builder;
            try {
                /**
                 * 查询名字等于 liming
                 * 并且年龄在30和35之间
                 */
                builder = JsonXContent.contentBuilder()
                        .startObject()
                        .startObject("query")

                        .startObject("bool")
                        .startObject("must")
                        .startObject("match")
                        .field("name.keyword", "liming")
                        .endObject()
                        .endObject()

                        .startObject("filter")
                        .startObject("range")
                        .startObject("age")
                        .field("gte", "30")
                        .field("lte", "35")
                        .endObject()
                        .endObject()
                        .endObject()
                        .endObject()

                        .endObject()
                        .endObject();
                indexRequest.source(builder);
            } catch (IOException e) {
                e.printStackTrace();
            }

            String source = indexRequest.source().utf8ToString();

            logger.info("source---->" + source);

            HttpEntity entity = new NStringEntity(source, ContentType.APPLICATION_JSON);

            Response response = ElasticsearchUtil.getLowLevelClient().performRequest("POST", endPoint, Collections.<String, String>emptyMap(), entity);
            return EntityUtils.toString(response.getEntity());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "查询数据出错";
    }

    /**
     * 根据id删除数据
     * @param id
     * @return
     * @throws IOException
     */
    public String deleteData(String id) throws IOException {
        DeleteRequest deleteRequest = new DeleteRequest("indexName", "type", id);
        DeleteResponse deleteResponse = client.delete(deleteRequest);
        return deleteResponse.getResult().toString();
    }

    /**
     * 删除查询的数据
     *
     * @return
     */
    @RequestMapping("/delByQuery")
    @ResponseBody
    public String delByQuery() {

        String deleteText = "chy";

        String endPoint = "/" + indexName + "/" + esType + "/_delete_by_query";

        /**
         * 删除条件
         */
        IndexRequest indexRequest = new IndexRequest();
        XContentBuilder builder;
        try {
            builder = JsonXContent.contentBuilder()
                    .startObject()
                    .startObject("query")
                    .startObject("term")
                    //name中包含deleteText
                    .field("name.keyword", deleteText)
                    .endObject()
                    .endObject()
                    .endObject();
            indexRequest.source(builder);
        } catch (IOException e) {
            e.printStackTrace();
        }

        String source = indexRequest.source().utf8ToString();

        HttpEntity entity = new NStringEntity(source, ContentType.APPLICATION_JSON);
        try {
            Response response = ElasticsearchUtil.getLowLevelClient().performRequest("POST", endPoint, Collections.<String, String>emptyMap(), entity);
            return EntityUtils.toString(response.getEntity());
        } catch (IOException e) {
            e.printStackTrace();
        }

        return "删除错误";
    }

    /**
     * 演示聚合统计
     *
     * @return
     */
    @RequestMapping("/aggregation")
    @ResponseBody
    public String aggregation() {
        try {
            String endPoint = "/" + indexName + "/" + esType + "/_search";

            IndexRequest indexRequest = new IndexRequest();
            XContentBuilder builder;
            try {
                builder = JsonXContent.contentBuilder()
                        .startObject()
                        .startObject("aggs")
                        .startObject("名称分组结果")
                        .startObject("terms")
                        .field("field", "name.keyword")
                        .startArray("order")
                        .startObject()
                        .field("_count", "asc")
                        .endObject()
                        .endArray()
                        .endObject()
                        .endObject()
                        .endObject()
                        .endObject();
                indexRequest.source(builder);
            } catch (IOException e) {
                e.printStackTrace();
            }

            String source = indexRequest.source().utf8ToString();

            logger.info("source---->" + source);

            HttpEntity entity = new NStringEntity(source, ContentType.APPLICATION_JSON);

            Response response = ElasticsearchUtil.getLowLevelClient().performRequest("POST", endPoint, Collections.<String, String>emptyMap(), entity);
            return EntityUtils.toString(response.getEntity());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "查询数据出错";
    }
}
